/* $RCSFile: CRMWrapperBase.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/CRMWrapper3/CRMWrapperBase.cs $
 * $log$
 * Revision 19 2011/02/22 01:23:08  christian.surieux
 *   V4 Migration 22/2/11
 * Revision 19 2011/02/22 01:22:24  christian.surieux
 *   V4 Migration 22/2/11
 * Revision 6 2010/08/06 19:56:32  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Threading;
using System.ComponentModel;
using System.Diagnostics;
using System.Security.Principal;
using System.Net;
using System.Xml;
using System.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Globalization;
using System.Web;
using System.Web.Configuration;
using System.Web.Services.Protocols;

using AddonNice.Settings;
using AddonNice.Settings.Cache;
using AddonNice.Security;


namespace AddonNice.CRMWrapper
{
	#region TraceSwitchs

	#region Base TraceSwitch classe that define some usefull properties
	public class ADNTraceSwitchW : TraceSwitch
	{
		public ADNTraceSwitchW()
			: base("DefaultTraceWrapper","Base Trace Switch for wrapper methods")
		{ }
		public ADNTraceSwitchW(string nm, string des)
			: base(nm, des)
		{ }
		public string Info{ get{ return string.Format("{0}-{1}",DisplayName,Level);}}
	}
	#endregion Base TraceSwitch classe that define some usefull properties
	#region Global TraceSwitch for CRM
	public class CRMTraceSwitch
	{
		static public ADNTraceSwitchW	Sw	=	new ADNTraceSwitchW("CRMTrace","Trace Switch for CRM");
	}
	#endregion TraceSwitch for CRM

	#region Query TraceSwitch for CRM
	public class CRMQueryTraceSwitch
	{
		static public ADNTraceSwitchW	Sw	=	new ADNTraceSwitchW("CRMQueryTrace","Trace Switch for CRM Queries");
	}
	#endregion Query TraceSwitch for CRM

	#region DynEntity TraceSwitch for CRM
	public class CRMDynTraceSwitch
	{
		static public ADNTraceSwitchW	Sw	=	new ADNTraceSwitchW("CRMDynTrace","Trace Switch for Dynamic entitieses");
	}
	#endregion DynEntity TraceSwitch for CRM

	#region Wrapper reset TraceSwitch for CRM
	public class CRMDynWrapperTrace
	{
		static public ADNTraceSwitchW	Sw	=	new ADNTraceSwitchW("CRMDynWrapperTrace","Trace Switch for Wrapper");
	}
	#endregion Wrapper reset for CRM

	#region CRM DynEntity Cache TraceSwitch for CRM
	public class CRMDynCacheTrace
	{
		static public ADNTraceSwitchW	Sw	=	new ADNTraceSwitchW("CRMDynCacheTrace","Trace Switch for Cache");
	}
	#endregion Wrapper reset for CRM
	#region Attributes TraceSwitch for CRM
	public class CRMMetaTrace
	{
		static public ADNTraceSwitchW	Sw	=	new ADNTraceSwitchW("CRMMetaTrace","Trace Switch for CRM Queries");
	}
	#endregion Attributes TraceSwitch for CRM

	#region TraceSwitch for install
	public class InstallTraceSwitchW 
	{
		static public ADNTraceSwitchW Sw = new ADNTraceSwitchW("InstallTrace", "Trace Switch for Install");
	}
	#endregion TraceSwitch for Install

	#endregion TraceSwitchs

	#region Wrapper Exception
	/// <summary>
	/// Exception class used inside crmwrapper, always fatal
	/// </summary>
	public class CRMWrapperException : Exception
	{
		/// <summary>
		/// Constructor to use when trigered without a previous SoapException
		/// </summary>
		public CRMWrapperException(string msg)
			: base(msg)
		{}
		/// <summary>
		/// Constructor to use when trigered after an earlier SoapException
		/// </summary>
		public CRMWrapperException(string msg, Exception inner)
			: base(msg, inner)
		{}
	}

	public class CRMNotFoundException : CRMWrapperException
	{
		/// <summary>
		/// Constructor to use when trigered without a previous SoapException
		/// </summary>
		public CRMNotFoundException(string msg)
			: base(msg)
		{}
		/// <summary>
		/// Constructor to use when trigered after an earlier SoapException
		/// </summary>
		public CRMNotFoundException(string msg, Exception inner)
			: base(msg, inner)
		{}
	}
	
	#endregion Exception

	#region event and delegate for CRMWrapper calls to be used by external classes

	public enum wrapperEventType { Unknown,Constructed, Starting, Started, UserIdSet, SysUserSet, AdminCreate, AdminRetrieve }; //TBD

	/// <summary>
	/// Define a custom EventArg class for wrapper events
	/// </summary>
	public class CrmWrapperEventArgs : EventArgs
	{
		public wrapperEventType WrapperType    =   wrapperEventType.Unknown;
		public object Sender                   = null;

		public CrmWrapperEventArgs(object sender,wrapperEventType tp)
		{
			Sender                  =   sender;
			WrapperType             =   tp;
		}
	}
	
	/// <summary>
	/// Define a new delegate which uses our custom eventArg class above
	/// </summary>
	public delegate void CrmWrapperEventHandler(object sender, CrmWrapperEventArgs e);

	#endregion delegate for CRMwrapper

	#region enums widely used

	public enum ADNAuthenticationType { AD=0 , Online=1, SPLA=2  }

	/// <summary>
	/// Enum used to map portal privileges to CRM
	/// </summary>
	public enum ADNCRMRights { ReadAccess, AddAccess, WriteAccess, DeleteAccess, EditAccess, AdminAccess };

	#endregion enums widely used

	#region delegates to use by external classes to interact with internal collections like entities and attributes
	
	public delegate void EntityNameDelegate(string entityName,string displayName);
	public delegate DynEntity DynEntityCopyDelegate(DynEntity s);
		
	public delegate bool BusinessEntityDelegate(InternalBusinessEntity bu);
	public delegate bool DynamicEntityDelegate(InternalDynamicEntity bu);
	public delegate bool DynamicEntityPropertyDelegate(string name,object val,object val2,object val3,AttributeInternalType tp);
	
	#endregion delegates to use by external classes to interact with internal collections like entities and attributes
	
	#region abstract classes for Web Services
	public abstract class CrmWebService
	{
		public abstract InternalResponse Execute(InternalRequest req);
		public abstract void Update(InternalBusinessEntity e);
		public abstract void Delete(string typename,Guid Id);
		public abstract InternalBusinessEntity Retrieve(string typename, Guid Id,InternalColumnSetBase col);
		public abstract InternalBusinessEntityCollection RetrieveMultiple(InternalQueryBase quer);
		public abstract Guid Create(InternalBusinessEntity e);
		public abstract string Fetch(string fetch1);
	}

	public abstract class CrmMetadataWebService
	{
		public abstract bool ExistEntityMetadata(string entityName);
		public abstract EntityInternalMetadata RetrieveEntityMetadata(string entityName, EntityInternalItems f);
		public abstract InternalMetadata RetrieveMetadata(EntityInternalItems f);
		public abstract InternalAttributeMetadata RetrieveAttributeMetadata(string entityName, string attributeName);
	}

	#endregion abstract classes for Web Services

	#region utilities enum
		
	public enum RouteType : int
	{
		Auto    =   0, // Specifies an automatic route. 
		User    =   1, // Specifies to route to a user's private queue. 
		Queue   =   2 //Specifies to route to a public queue. 
	}

	#endregion utilities enum

	/// <summary>
	/// Main class to ,communicate with CRM WebService
	/// </summary>
	public abstract class CRMWrapperBase
	{
		#region local variables

		protected Guid _businessUnitId                      =   Guid.Empty;
	   
		/// <summary>
		/// Admin CRM account
		/// </summary>
		protected abstract string CRMServiceAccount
		{ get; set; }
		protected abstract string CRMServicePassword
		{ get; set; }
		protected abstract string CRMServiceDomain
		{ get; set; }

		/// <summary>
		/// Default eg anonymous CRM account
		/// </summary>
		protected abstract string CRMServiceDefaultAccount
		{ get; set; }
		protected abstract string CRMServiceDefaultPassword
		{ get; set; }
		protected abstract string CRMServiceDefaultDomain
		{ get; set; }

		/// <summary>
		/// PrivateUser Group member
		/// </summary>
		protected abstract string CRMPrivAccount
		{ get; set; }
		protected abstract string CRMPrivPassword
		{ get; set; }
		protected abstract string CRMPrivDomain
		{ get; set; }

		protected bool _isAdminInitialized                  =   false;
		protected bool _isInitialized                       =   false;
		protected CrmMetadataWebService _userMetaService    =   null;
		protected CrmMetadataWebService _adminMetaService   =   null;
		protected string _DownloadServerUrl                 =   string.Empty;

		public CRMUtil Util                                 =   null;
		protected ADNDynBusinessUnit _InnerBusinessUnit     =   null;
		protected Guid _OrganizationId                      =   Guid.Empty;
		protected string _OrganizationName                  =   string.Empty;
		protected string _OrganizationFriendlyName          =   string.Empty;

		protected string _SchemaNamePrefix                  =   string.Empty;
		protected int    _FullNameFormat                    =   -1;
		protected string _FullNameFormatName                =   string.Empty;

		protected string _CrmBackupFolder                   =   string.Empty;

	 
		public abstract ADNAuthenticationType AuthenticationType
		{
			get; set;
		}

		/// <summary>
		/// Read-only access to service url
		/// </summary>
		public string CrmServiceUrl
		{
			get
			{
				return ServiceUrl;
			}
		}

		protected abstract string ServiceUrl
		{ get; set;}
		
		protected virtual string MetaDataServiceUrl
		{ get; set;}
		
		protected virtual string WebApplicationUrl
		{ get; set;}

		public virtual string OrganizationName
		{
			get
			{
				return _OrganizationName;
			}
			set
			{
				_OrganizationName   =   value;
			}
		}

		public virtual string OrganizationFriendlyName
		{
			get
			{
				return _OrganizationFriendlyName;
			}
			set
			{
				_OrganizationFriendlyName   =   value;
			}
		}

		public virtual Guid OrganizationId
		{
			get
			{
				return _OrganizationId;
			}
			set
			{
				_OrganizationId    =   value;
			}
		}
		
		public ADNDynBusinessUnit InnerBusinessUnit
		{
			get
			{
				if ( _InnerBusinessUnit == null )
				{
					SortedDictionary<Guid, ADNDynBusinessUnit> dbc  =    GetAllBusinessUnits();
					if ( _InnerBusinessUnit == null )
						foreach ( Guid key in dbc.Keys )
						{
							ADNDynBusinessUnit dbu                  =   dbc[key];
							if ( dbu.parentbusinessunitid == Guid.Empty )
							{
								_InnerBusinessUnit                  =   dbu;
								break;
							}
						}
					}
				return _InnerBusinessUnit;
			}
		}

		public virtual string CrmVersion
		{
			get
			{
				return CrmStr.CrmVersion3;
			}
		}

		public abstract ADNDynSystemUser GetUserById2(Guid uId);
		public abstract ADNDynSystemUser GetUserByDomainName2(string name);


		/// <summary>
		/// Check some user against our Crm: false if not recognized
		/// </summary>
		public  abstract bool IsUserOk4Crm(string domain,string login,string pwd);
		

		/// <summary>
		/// Url used for downloading documents/Attachments from Crm
		/// </summary>
		public abstract string DownloadServerUrl
		{   get;}

		public virtual byte[] DownLoadFile(string url,ref bool OkDownload)
		{ return null; }

		/// <summary>
		/// Url used for Crm customizations backup before any 'risky' action'
		/// Should be on AddonNice Server and CrmUsers should have a write access on it
		/// Installed by portal after Initialize, if not set, returns tempfile folder
		/// normally ApplicationRoot/PortalPath/CrmBackup/Default
		/// </summary>
		public virtual string CrmBackupFolder
		{
			get
			{
				if (string.IsNullOrEmpty(_CrmBackupFolder))
					return System.IO.Path.GetTempPath();
				return _CrmBackupFolder;
			}
			set
			{
				_CrmBackupFolder    =   value;
			}
		}
		
		#endregion local variables

		#region wrapper delegate

		public static event CrmWrapperEventHandler CrmWrapperEvent;

		// Call back on main wrapper events 
		public void OnCrmWrapperEvent(CrmWrapperEventArgs e)
		{
			if ( CrmWrapperEvent != null )
				CrmWrapperEvent(this,e);
		}

		#endregion wrapper delegate

		#region IFrameDetection
		
		Guid _requestEntityID = Guid.Empty;
		/// <summary>
		/// This is the current entity for which we have loaded the iFrame
		/// Value come from the request parameter 'id' sent by the CRM iFrame (dont forget to ask it to send the parameter)
		/// </summary>
		public Guid RequestEntityID
		{
			get
			{
				if (Guid.Empty == _requestEntityID && HttpContext.Current != null)
				{
					string obj          =   HttpContext.Current.Request[CrmStr.strCrmID];
					if (!string.IsNullOrEmpty(obj))
						_requestEntityID  =   new Guid(obj);
				}
				return _requestEntityID;
			}
		}

		public static string RequestEntityIDStr
		{
			get
			{
				if ( HttpContext.Current != null)
				{
					string obj          =   HttpContext.Current.Request[CrmStr.strCrmID];
					if (!string.IsNullOrEmpty(obj))
						return   (string)obj;
				}
				return string.Empty;
			}
		}
		
		bool? _IsCrmEntityID =   null;
		/// <summary>
		/// Crm sends the id query string with {} surounding the guid value, not AddonNice
		/// We use this to differenciate internal and external calls
		/// </summary>
		public bool IsCrmEntityID
		{
			get
			{
				if ( !_IsCrmEntityID.HasValue && HttpContext.Current != null)
				{
					string obj = HttpContext.Current.Request[CrmStr.strCrmID];
					if (!string.IsNullOrEmpty(obj))
						_IsCrmEntityID = (obj.IndexOf('{') > -1 );
					else _IsCrmEntityID = false;
				}
				return _IsCrmEntityID.HasValue ? _IsCrmEntityID.Value:false;
			}
		}

		/// <summary>
		/// When in creation mode we have no entityID, this is the reason why
		/// We add a Crm marker in the iframe url /site/ucrm_1/PageId/xxx.aspx
		/// </summary>
		public bool RequestHasCrmMark
		{
			get
			{
				if ( HttpContext.Current != null)
				{
					string obj = HttpContext.Current.Request[CrmStr.strCrmMark];
					if (!string.IsNullOrEmpty(obj))
						return true;
					return false;
				}
				return false;
			}
		}


		string _requestEntityTypename   =   string.Empty;
		/// <summary>
		/// Get the entity sent by CRM iFrame as parameter
		/// Comparing it with local EntityName for pages or modules allow to see if we are inside the custom entity attached to this page
		/// Value come from the request parameter 'typename' sent by the CRM iFrame (dont forget to ask it to send the parameter)
		/// </summary>
		public string RequestEntityTypename
		{
			get
			{
				if ( string.IsNullOrEmpty(_requestEntityTypename) && HttpContext.Current != null )
				{
					object obj      =   HttpContext.Current.Request[CrmStr.strCrmTypeName];
					if (obj != null && obj is string)
						_requestEntityTypename =   (string)obj;

				}
				return _requestEntityTypename;
			}
		}

		string _requestEntityTypeCode   =   string.Empty;
		/// <summary>
		/// Get EntityType from parametres sent by CRM to the iFrame Field contaning our Module
		/// </summary>
		public string RequestEntityTypeCode
		{
			get
			{
				if (string.IsNullOrEmpty(_requestEntityTypeCode) && ( HttpContext.Current != null) )
				{
					object obj = HttpContext.Current.Request[CrmStr.strCrmType];
					if (obj != null && obj is string)
						_requestEntityTypeCode  =   (string)obj;

				}
				return _requestEntityTypeCode;
			}
		}

		/// <summary>
		/// CRM V4
		/// Get the orgname sent by CRM iFrame as parameter
		/// Organization Name The unique name of the organization. 
		/// </summary>
		string _RequestOrgName = string.Empty;
		public virtual string RequestOrgName
		{
			get
			{
				if (string.IsNullOrEmpty(_RequestOrgName) && HttpContext.Current != null)
				{
					string str              =   HttpContext.Current.Request[CrmStr.strOrgName];
					if (!string.IsNullOrEmpty(str))
						_RequestOrgName  =   str;
				}
				return _RequestOrgName;
			}
		}

		/// <summary>
		/// Localize if not under Crm, or Crm v3
		/// else if under Crm and UserLCID != OrgLCID
		/// </summary>
		public bool ShouldLocalize
		{
			get
			{
				if ( !IsUnderCRM )
					return true;
				if ( CrmVersion == CrmStr.CrmVersion3 )
					return true;
				if ( RequestUserLCID == RequestOrgLCID )
					return false;
				return true;
			}
		}
		
		public int RequestUserBaseLCID
		{
			get
			{
				return baseLCID(RequestUserLCID);
			}
		}

		int _requestUserLCID        =   -1;
		/// <summary>
		/// CRM V4
		/// User LCID sent in request string by CRM from v4, 
		/// Current Thread UICulture LCID when not initialized or v3
		/// </summary>
		public int RequestUserLCID
		{
			get
			{
				if ( -1 == _requestUserLCID && HttpContext.Current != null)
				{
					string obj = HttpContext.Current.Request[CrmStr.strUserLCID];
					if ( !string.IsNullOrEmpty(obj) && int.TryParse(obj,out _requestUserLCID) )
							return _requestUserLCID;
					return Thread.CurrentThread.CurrentUICulture.LCID;
				}
				return _requestUserLCID;
			}
		}
		
		public int baseLCID(int LCID)
		{
			CultureInfo lang    =	new CultureInfo(LCID);
			int newLCID         =   LCID;
			if ( ( lang.Parent == null ) || ( lang.Parent.LCID == lang.LCID ) )
					newLCID =   lang.Parent.LCID;
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase baseLCID LCID: {0}, newLCID: {1}",LCID,newLCID),CRMTraceSwitch.Sw.Info);
			return newLCID;
		}

		/// <summary>
		/// Test if CrmOrg LCID is a child of sent LCID
		/// Because DefLCID in DB is always a base language LCID
		/// </summary>
		public bool IsParentOfCrmOrgLCID(int LCID)
		{
			int CLC                 =   RequestOrgLCID;
			while ( CLC != LCID )
			{
				CultureInfo lang    =	new CultureInfo(CLC);
				if ( ( lang.Parent == null ) || ( lang.Parent.LCID == lang.LCID ) )
					break;
				CLC                 =   lang.Parent.LCID;   
				if ( CLC == LCID )
					break;
			}
			bool isParent           =   ( CLC == LCID );
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase IsParentOfCrmOrgLCID LCID: {0}, isParent: {1}",LCID,isParent),CRMTraceSwitch.Sw.Info);
			return isParent;
		}

		int _requestOrgLCID        =   -1;
		/// <summary>
		/// CRM V4
		/// Org LCID sent in request string by CRM from v4, -1 when not initialized or v3
		/// </summary>
		public int RequestOrgLCID
		{
			get
			{
				if ( -1 == _requestOrgLCID && HttpContext.Current != null)
				{
					string obj = HttpContext.Current.Request[CrmStr.strOrgLCID];
					if ( !string.IsNullOrEmpty(obj) && int.TryParse(obj,out _requestOrgLCID) )
							return _requestOrgLCID;
					return Thread.CurrentThread.CurrentUICulture.LCID;
				}
				return _requestOrgLCID;
			}
		}
		
		
		string _requestUserLCIDStr = string.Empty;

		/// <summary>
		/// CRM V4
		/// userlcid User Language Code The language code identifier that is used by the current user. 
		/// </summary>
		public virtual string RequestUserLCIDStr
		{
			get
			{
				if (string.IsNullOrEmpty(_requestUserLCIDStr) && HttpContext.Current != null)
				{
					string str              =   HttpContext.Current.Request[CrmStr.strUserLCID];
					if (!string.IsNullOrEmpty(str))
						_requestUserLCIDStr  =   str;
				}
				return _requestUserLCIDStr;
			}
		}


		string _requestOrgLCIDStr = string.Empty;
		/// <summary>
		/// CRM V4
		/// orglcid Organization Language Code The language code identifier that represents the base language for the organization. 
		/// </summary>
		public virtual string RequestOrgLCIDStr
		{
			get
			{
				if (string.IsNullOrEmpty(_requestOrgLCIDStr) && HttpContext.Current != null)
				{
					string str              =   HttpContext.Current.Request[CrmStr.strOrgLCID];
					if (!string.IsNullOrEmpty(str))
						_requestOrgLCIDStr  =   str;
				}
				return _requestOrgLCIDStr;
			}
		}
		
		/// <summary>
		/// Is the module called from a CRM iFrame
		/// </summary>
		public virtual bool IsUnderCRM
		{
			get
			{
				return ( RequestHasCrmMark || (!string.IsNullOrEmpty(RequestEntityTypename) && IsCrmEntityID ));
			}
		}

		/// <summary>
		/// Used to check the management mode
		/// </summary>
		public virtual bool IsInEntityCreationMode
		{
			get
			{
				bool ret    =   ( IsUnderCRM && RequestEntityID == Guid.Empty) ;
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase IsInEntityCreationMode: {0}", ret),CRMTraceSwitch.Sw.Info);
				return ret;
			}
		}

		// used to simulate the behaviour of modules under CRM when called outside ou CRM
		private bool _CRMSimulationInitiated    =   false;
		private bool _CRMSimulation             =   false;
		public bool CRMSimulation
		{
			get
			{
				if (!_CRMSimulationInitiated && HttpContext.Current != null && HttpContext.Current.Session != null)
				{
					object obj              = HttpContext.Current.Session["CRMSimulation"];
					if (obj != null && obj is bool )
						_CRMSimulation      = (bool)obj;
					_CRMSimulationInitiated = true;
				}
				return _CRMSimulation;
			}
			set
			{
				_CRMSimulation = value;
				if (HttpContext.Current != null && HttpContext.Current.Session != null)
				{
					HttpContext.Current.Session["CRMSimulation"] = value;
				}
			}
		}

		public bool IsCRMSimulation
		{
			get
			{
				return CRMSimulation;
			}
		}

		#endregion IFrameDetection


		#region Ctor and installing wrapper

		/// <summary>
		/// Create a new CRM Wrapper but DO NOT initialize it
		/// Initialization should be done only when user is authenticated
		/// CRM Service Setup for CRM 3
		/// </summary>
		protected CRMWrapperBase(string wurl,string wCRMServiceAccount,string wCRMServicePassword,string wCRMServiceDomain,
			string wCRMDefaultAccount,string wCRMDefaultAccountPwd,string wCRMDefaultAccountDn, 
						string wCRMPrivAccount,string wCRMPrivPassword,string wCRMPrivDomain)
		{
			// Standard CRM Service Setup
			ServiceUrl                  =	wurl.ToLower();
			MetaDataServiceUrl          =	wurl.Replace("crmservice.asmx","metadataservice.asmx");
			CRMServiceAccount           =   wCRMServiceAccount;
			CRMServicePassword          =   wCRMServicePassword;
			CRMServiceDomain            =   wCRMServiceDomain;

			CRMServiceDefaultAccount    =   wCRMDefaultAccount;
			CRMServiceDefaultPassword   =   wCRMDefaultAccountPwd;
			CRMServiceDefaultDomain     =   wCRMDefaultAccountDn;

			CRMPrivAccount              =   wCRMPrivAccount;
			CRMPrivPassword             =   wCRMPrivPassword;
			CRMPrivDomain               =   wCRMPrivDomain;
		}

		/// <summary>
		/// Create a new CRM Wrapper but DO NOT initialize it
		/// Initialization should be done only when user is authenticated
		/// CRM Service Setup for CRM4
		/// </summary>
		protected CRMWrapperBase(string wCRMServiceAccount,string wCRMServicePassword,string wCRMServiceDomain,
						string wCRMDefaultAccount,string wCRMDefaultAccountPwd,string wCRMDefaultAccountDn, 
						string wCRMPrivAccount,string wCRMPrivPassword,string wCRMPrivDomain,ADNAuthenticationType authTp)
		{
			AuthenticationType          =   authTp; // Must be first !!!
			CRMServiceAccount           =   wCRMServiceAccount;
			CRMServicePassword          =   wCRMServicePassword;
			CRMServiceDomain            =   wCRMServiceDomain;
			
			CRMServiceDefaultAccount    =   wCRMDefaultAccount;
			CRMServiceDefaultPassword   =   wCRMDefaultAccountPwd;
			CRMServiceDefaultDomain     =   wCRMDefaultAccountDn;

			CRMPrivAccount              =   wCRMPrivAccount;
			CRMPrivPassword             =   wCRMPrivPassword;
			CRMPrivDomain               =   wCRMPrivDomain;
		}

		#region services initialization

		/// <summary>
		/// Initialize a wrapper
		/// Initialization should be done only when user is authenticated
		/// </summary>
		public virtual void Initialize(bool UsePreAuthenticate)
		{
			if (!isInitialized)
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]CRMWrapperBase Initialize BEG.",CRMTraceSwitch.Sw.Info);
				// Dispatch a starting event to all requesting objects
				CrmWrapperEventArgs ev      =   new CrmWrapperEventArgs(this,wrapperEventType.Starting);
				OnCrmWrapperEvent(ev);

				if (HttpContext.Current != null)
				{
					AuthenticationMode auth	=	Config.AuthenticationMode;
					// We are not logged and want to logon, so we need some user, just to test license without throwing an exception
					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase Initialize Request.IsAuthenticated: {0}",HttpContext.Current.Request.IsAuthenticated),CRMTraceSwitch.Sw.Info);
					if (!HttpContext.Current.Request.IsAuthenticated && auth != AuthenticationMode.Forms )
					{
						const string msg    =   "[E]CRMWrapperBase Initialize User not authenticated.";
						if ( CRMTraceSwitch.Sw.TraceError || SecurityTraceSwitch.Sw.TraceError || AuthenticationTrace.Sw.TraceError )
						{
							string nfo      =   CRMTraceSwitch.Sw.Info;
							if ( SecurityTraceSwitch.Sw.TraceError )
								nfo         =   SecurityTraceSwitch.Sw.Info;
							else if ( AuthenticationTrace.Sw.TraceError )
								nfo         =   AuthenticationTrace.Sw.Info;
							Trace.WriteLine(msg, nfo);
						}
						throw new CRMWrapperException(msg);
					}
				}
				InitServices(UsePreAuthenticate);
				ReadCurrentOrganization();
				// Dispatch a started event to all requesting objects
				ev                          =   new CrmWrapperEventArgs(this,wrapperEventType.Started);
				OnCrmWrapperEvent(ev);
				
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]CRMWrapperBase Initialize END.",CRMTraceSwitch.Sw.Info);
			}
		}

		/// <summary>
		/// Flag to avoid several admin initializations of wrapper and to check if admin initialization is finished
		/// </summary>
		public bool isAdminInitialized
		{
			get { return _isAdminInitialized; }
		}

		/// <summary>
		/// Flag to avoid several initializations of wrapper and to check if initialization is finished
		/// </summary>
		public bool isInitialized
		{
			get { return _isInitialized; }
		}


		/// <summary>
		/// Current user name
		/// </summary>
		public abstract string userName
		{
			get;
		}

		/// <summary>
		/// Current user typeCode
		/// </summary>
		public int userTypeCode
		{
			get
			{
				return (int)ADNTypeCodes.SystemUser;
			}
		}

		/// <summary>
		/// BusinessUnit of current user
		/// </summary>
		public abstract Guid businessUnitId
		{
			get;
		}

		/*
		/// <summary>
		/// When we  call this method from an iFrame, the identity may be different from logged user
		/// then we need to impersonate to logged user
		/// this property is the corresponding indicator 
		/// </summary>
		protected abstract bool impersonateUser
		{
			get;
		}
		*/

		/// <summary>
		/// Domain name for the admin account
		/// </summary>
		public abstract string adminUserName
		{
			get;
		}


		/// <summary>
		/// The Guid corresponding to the authentified user, obtained with whoAmI using userService
		/// </summary>
		public abstract Guid userId
		{
			get;
			set;
		}
		
		/// <summary>
		/// Guid of CRM administrator specified in config file
		/// </summary>
		public abstract Guid adminUserId
		{ get;}

		public abstract string SqlAccessGroupName
		{ get;}

		public abstract Guid SqlAccessGroupId
		{ get;}

		public abstract string ReportingGroupName
		{ get;}

		public abstract Guid ReportingGroupID
		{ get;}

		public abstract Guid UserGroupId
		{ get;}

		/// <summary>
		/// Organization language code
		/// </summary>
		public abstract int LanguageCode
		{ get;}

		/// <summary>
		/// Organization currency Symbol, to synch with AddonNice
		/// </summary>
		public abstract string CurrencySymbol
		{ get;}

		/// <summary>
		/// Not defined in V3, returns Guid.Empty
		/// </summary>
		public abstract Guid BaseCurrencyId 
		{ get;}


		/// <summary>
		/// Prefix used for custom entities and attributes schema names
		/// </summary>
		public virtual string SchemaNamePrefix
		{
			get
			{
				return _SchemaNamePrefix;
			}
			set
			{
				_SchemaNamePrefix    =   value;
			}
		}

		public virtual int FullNameFormat
		{
			get
			{
				return _FullNameFormat;
			}
			set
			{
				_FullNameFormat    =   value;
			}
		}

		public virtual string FullNameFormatName
		{
			get
			{
				return _FullNameFormatName;
			}
			set
			{
				_FullNameFormatName    =   value;
			}
		}

		/// <summary>
		/// Utility to create a fullname using current settings
		/// </summary>
		public virtual string MakeFullName(string firstName,string lastName,string midName)
		{
			if ( CRMTraceSwitch.Sw.TraceError )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase MakeFullName BEG FullNameFormat: {0}, FullNameFormatName: {1}.",FullNameFormat,FullNameFormatName),CRMTraceSwitch.Sw.Info);
			string result   =   lastName;
			switch (FullNameFormat)
			{
				case 0: //Last Name, First Name 
					result= string.Format("{0}, {1}",lastName,firstName);
					break;
				case 1: //First Name
					result= firstName;
					break;

				case 2: //Last Name, First Name, Middle Initial
					result= string.Format("{0}, {1}, {2}",lastName,firstName,midName);
					break;

				case 3: //First Name, Middle Initial, Last Name
					result= string.Format("{0}, {1}, {2}",firstName,midName,lastName);
					break;

				case 4: //Last Name, First Name, Middle Name
					result= string.Format("{0}, {1}, {2}",lastName,firstName,midName);
					break;

				case 5: //First Name, Middle Name, Last Name
					result= string.Format("{0}, {1}, {2}",firstName,midName,lastName);
					break;

				case 6: //Last Name, space, First Name
					result= string.Format("{0} {1}",lastName,firstName);
					break;

				case 7: //Last Name, no space, First Name
					result= string.Format("{0}{1}",lastName,firstName);
					break;
			}
			if ( CRMTraceSwitch.Sw.TraceError )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase MakeFullName END result: {0}.",result),CRMTraceSwitch.Sw.Info);
			return result;
		}

		/// <summary>
		/// General Initialisation of web services instances
		/// adminAdminService is using an admin credential
		/// adminService is impersonating over the authentified user with an administrator account
		/// userService is using the authentified user credential
		/// </summary>
		protected abstract void InitAdminService(bool UsePreAuthenticate);
		protected abstract void InitServices(bool UsePreAuthenticate); 
		protected abstract void ReadCurrentOrganization(); 

		#endregion services initialization
		
		#endregion Ctor and installing wrapper

		#region Services objects

		protected abstract CrmWebService userService
		{   get;}

		protected abstract CrmWebService adminService
		{   get;}

		protected abstract CrmWebService adminAdminService
		{   get;}

		public abstract CrmMetadataWebService userMetaService
		{   get;}

		public abstract CrmMetadataWebService adminMetaService
		{   get;}

		#endregion services objects
		
		#region Main API calls

		/// <summary>
		/// Safe Execute
		/// </summary>
		public InternalResponse userExecute(InternalRequest r)
		{
			InternalResponse rep    =   null;
			try
			{
				rep = userService.Execute(r);
			}
			catch (SoapException sx)
			{
				string msg  =   string.Format("[E]CRMWrapperBase userExecute  ex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg     =   "[E]CRMWrapperBase userExecute Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase Execute ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw;
			}
			return rep;
		}

		/// <summary>
		/// Safe Update for normal entities (versus compound)
		/// </summary>
		public InternalResponse userUpdate(InternalUpdateRequest r)
		{
			InternalResponse rep = null;
			try
			{
				rep = (InternalResponse)userService.Execute(r);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase userUpdate sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase userUpdate Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase userUpdate ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw;
			}
			return rep;
		}

		/// <summary>
		/// Safe Update for compound entities (SalesOrders, Invoices, Quotes)
		/// </summary>
		public InternalResponse userUpdate(InternalRequest r)
		{
			InternalResponse rep = null;
			try
			{
				rep = (InternalResponse)userService.Execute(r);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase userUpdate sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase userUpdate Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase userUpdate Compound ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw;
			}
			return rep;
		}

		/// <summary>
		/// Safe Create for Create requests
		/// </summary>
		public InternalResponse Create(InternalRequest create,bool isAdmin)
		{
			InternalResponse rep = null;
			try
			{
				if ( isAdmin) 
					rep = adminService.Execute(create);
				else 
					rep = userService.Execute(create);
			}
			catch (SoapException sx)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase Create isAdmin: {0}, ex: {1}-{2}",isAdmin,sx, sx.Detail.InnerText),CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException("userCreate soap: " + sx.Detail.InnerText, sx);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase Create isAdmin: {0}, ex: {1}",isAdmin,ex),CRMTraceSwitch.Sw.Info);
				throw;
			}
			return rep;
		}
		
		#region Create compound operations

		/// <summary>
		/// Dynamic create compound entity with the user account
		/// </summary>
		public abstract Guid userCreateCompound(InternalTargetCompound target);
		public abstract Guid userCreateCompound(DynEntity entity,List<DynEntity> childs);

		/// <summary>
		/// Dynamic create compound entity with the admin account
		/// </summary>
		public abstract Guid adminCreateCompound(InternalTargetCompound target);
		public abstract Guid adminCreateCompound(DynEntity entity,List<DynEntity> childs);

		#endregion Create compound operations

		#region Rollup operations

		public abstract InternalResponse userRollup(string entityNm,Guid Id,InternalQueryBase quer,bool isDynamic);
		public abstract InternalResponse userRollup(DynEntity entity,InternalQueryBase quer);
		public abstract InternalResponse adminRollup(string entityNm,Guid Id,InternalQueryBase quer,bool isDynamic);
		public abstract InternalResponse adminRollup(DynEntity entity,InternalQueryBase quer);
		
		#endregion Rollup operations

		/// <summary>
		/// Safe Delete
		/// </summary>
		public InternalResponse userDelete(InternalRequest delete)
		{
			InternalResponse rep = null;
			try
			{
				rep = userService.Execute(delete);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase userDelete sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase userDelete Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (CRMWrapperException)
			{
				throw;
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase userDelete ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException("userDelete ex", ex);
			}
			return rep;
		}


		/// <summary>
		/// Safe Execute with impersonation on an admin account
		/// </summary>
		public InternalResponse adminExecute(InternalRequest r)
		{
			InternalResponse rep = null;
			try
			{
				rep = adminService.Execute(r);
			}
			catch (SoapException sx)
			{
				string msg  =   string.Format("[E]CRMWrapperBase AdminExecute ex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg     =   "[E]CRMWrapperBase AdminExecute Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (CRMWrapperException)
			{
				throw;
			}
			catch (Exception ex)
			{
				string msg  =   string.Format("[E]CRMWrapperBase AdminExecute ex: {0}", ex);
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException(msg, ex);
			}
			return rep;
		}

		/// <summary>
		/// Super Safe Execute with credentials on the same admin account
		/// </summary>
		public InternalResponse adminAdminExecute(InternalRequest r)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase adminAdminExecute BEG Request: {0}", r),CRMTraceSwitch.Sw.Info);
			InternalResponse rep = null;
			try
			{
					rep = adminAdminService.Execute(r);
			}
			catch (SoapException sx)
			{
				string msg  =   string.Format("[E]CRMWrapperBase adminAdminExecute ex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg     =   "[E]CRMWrapperBase adminAdminExecute Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase adminAdminExecute ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException("adminAdminExecute ex", ex);
			}
			return rep;
		}

		
		/// <summary>
		/// Safe Update for entities
		/// </summary>
		public void Update(InternalBusinessEntity e, bool admin)
		{
			try
			{
				if (!admin)
						userService.Update(e);
				else    adminService.Update(e);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase Update sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase Update Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase Update ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw;
			}
		}

		/// <summary>
		/// Safe Delete for entities
		/// </summary>
		public void Delete(string typename,Guid Id, bool admin)
		{
			try
			{
				if (!admin)
						userService.Delete(typename,Id);
				else    adminService.Delete(typename, Id);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase Delete sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase Delete Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase Delete ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw;
			}
		}

		/// <summary>
		/// Safe Retrieve for entities
		/// </summary>
		public InternalBusinessEntity Retrieve(string typename, Guid Id,InternalColumnSetBase  col , bool admin)
		{
			InternalBusinessEntity bu = null;
			
			try
			{
				if (!admin)
					 bu     =   userService.Retrieve(typename, Id, col);
				else bu     =   adminService.Retrieve(typename, Id, col);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase Retrieve sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase Retrieve Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase Retrieve ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw;
			}
			return bu;
		}

		/// <summary>
		/// Safe Multiple Retrieve for entities
		/// </summary>
		public InternalBusinessEntityCollection RetrieveMultiple(InternalQueryBase quer, bool admin)
		{
			InternalBusinessEntityCollection bu = null;

			try
			{
				if (!admin)
						bu = userService.RetrieveMultiple(quer);
				else    bu = adminService.RetrieveMultiple(quer);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase RetrieveMultiple sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase RetrieveMultiple Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase RetrieveMultiple ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw;
			}
			return bu;
		}


		/// <summary>
		/// Safe Create for entities
		/// </summary>
		public Guid Create(InternalBusinessEntity e,bool admin)
		{
			Guid wid = Guid.Empty;
			try
			{
				if ( !admin )
					wid = userService.Create(e);
				else
					wid = adminService.Create(e);
			}
			catch (SoapException sx)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase Create ex: {0}-{1}", sx, sx.Detail.InnerText),CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException("Create soap: " + sx.Detail.InnerText, sx);
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase Create ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw;
			}
			return wid;
		}
		#endregion Main API calls

		#region Utilities

		public abstract InternalRetrieveMultipleRequest MakeRetrieveMultipleRequest(InternalQueryExpression query, bool isDynamic);
		public abstract InternalTargetCompoundDynamic MakeTargetCompoundDynamic(InternalDynamicEntity entity,InternalDynamicEntity[] childs);
		public abstract InternalTargetCompoundDynamic MakeTargetCompoundDynamic(DynEntity entity,List<DynEntity> childs);

		/// <summary>
		/// Retrieve the active user count (to check license) in CRM
		/// Set it in cache for 20mn to reduce webservice usage
		/// </summary>
		public int ActiveUsersCount
		{
			get
			{
				string ckey						= "ActiveUsersCount";
				if (CurrentCache.Exists(ckey))
					return (int)CurrentCache.Get(ckey);

				int userCount					= 0; //internal users count
				try
				{
					// Only fetchxml supports aggregates
					string fetch1				= "<fetch mapping=\"logical\" aggregate=\"true\"><entity name=\"systemuser\">"
						+"<attribute name=\"systemuserid\" aggregate=\"count\" alias=\"Count\"/>"
						+"<filter><condition attribute=\"isdisabled\" operator=\"eq\" value=\"false\" /></filter></entity></fetch>";

					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase ActiveUsersCount fetch1: {0}", fetch1),CRMTraceSwitch.Sw.Info);
					// Fetch the results.
					string result				= string.Empty;
					if (isInitialized)
						result					= adminAdminService.Fetch(fetch1);
					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase ActiveUsersCount result: {0}", result),CRMTraceSwitch.Sw.Info);
					// It returns the number of active users in the following format:
					//<resultset morerecords="0">
					//<result>
					//<Count>9</Count>
					//</result>
					//</resultset>

					if ( string.IsNullOrEmpty(result) )
						return 0;
					StringReader strm			= null;
					XmlReader rdr				= null;
					try
					{
						strm					= new StringReader("<?xml version='1.0'?>" + result);
						rdr						= XmlReader.Create(strm);
						while (!rdr.EOF)
						{
							if (rdr.IsStartElement("Count"))
							{
								userCount		= rdr.ReadElementContentAsInt();
								if ( CRMTraceSwitch.Sw.TraceVerbose )
									Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase ActiveUsersCount read : {0}", userCount),CRMTraceSwitch.Sw.Info);
								CurrentCache.InsertMinutes(ckey, userCount,20); //insert in cache for 5 mn
								break;
							}
							rdr.Read();
						}
					}
					catch (Exception ex)
					{
						if ( CRMTraceSwitch.Sw.TraceError )
							Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase ActiveUsersCount Reading xml ex: {0}, XMLResult: {1}", ex,result),CRMTraceSwitch.Sw.Info);
						throw new CRMWrapperException("ActiveUsersCount Ex", ex);
					}
					finally
					{
						if ( rdr != null )
							rdr.Close();
						if ( strm != null )
							strm.Close();
					}
			   }
				catch (SoapException sx)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase ActiveUsersCount  sex: {0}-{1}", sx, sx.Detail.InnerText),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("ActiveUsersCount Sx", sx);
				}
				catch (CRMWrapperException)
				{
					throw;
				}
				catch (Exception ex)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase ActiveUsersCount ex: {0}", ex),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("ActiveUsersCount Ex", ex);
				}
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase ActiveUsersCount Count: {0}", userCount),CRMTraceSwitch.Sw.Info);
				return userCount;
			}
		}
		

		/// <summary>
		/// Retrieve the active user count (to check license) in CRM
		/// Set it in cache for 20mn to reduce webservice usage
		/// </summary>
		public int FetchCount(string schemaName,string primaryKeyName,string extFilter, bool all)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase FetchCount BEG schemaName: {0}, all: {1}, primaryKeyName: {2}, extFilter: {3}",
					new object[]{schemaName, all,primaryKeyName,extFilter}),CRMTraceSwitch.Sw.Info);
			int Count					    =   0; 
			StringBuilder sb                =   new StringBuilder();
			try
			{
				// Only fetchxml supports aggregates
				sb.AppendFormat("<fetch mapping=\"logical\" aggregate=\"true\"><entity name=\"{0}\">",schemaName);
				sb.AppendFormat("<attribute name=\"{0}\" aggregate=\"count\" alias=\"Count\"/>",primaryKeyName);
				if ( !string.IsNullOrEmpty(extFilter) )
					sb.Append(extFilter);
				//sb.Append("<filter><condition attribute=\"isdisabled\" operator=\"eq\" value=\"false\" /></filter>");
				sb.Append("</entity></fetch>");
				string fetch1				=   sb.ToString();
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase FetchCount fetch1: {0}", fetch1),CRMTraceSwitch.Sw.Info);
				// Fetch the results.
				string result				=   string.Empty;
				if (isInitialized)
					result					=   adminAdminService.Fetch(fetch1);
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase FetchCount result: {0}", result),CRMTraceSwitch.Sw.Info);
				// It returns the number in the following format:
				//<resultset morerecords="0">
				//<result>
				//<Count>9</Count>
				//</result>
				//</resultset>

				if ( string.IsNullOrEmpty(result) )
					return 0;
				StringReader strm			=   null;
				XmlReader rdr				=   null;
				try
				{
					strm					=   new StringReader("<?xml version='1.0'?>" + result);
					rdr						=   XmlReader.Create(strm);
					while (!rdr.EOF)
					{
						if (rdr.IsStartElement("Count"))
						{
							Count		    =   rdr.ReadElementContentAsInt();
							if ( CRMTraceSwitch.Sw.TraceVerbose )
								Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase FetchCount read : {0}", Count),CRMTraceSwitch.Sw.Info);
							break;
						}
						rdr.Read();
					}
				}
				catch (Exception ex)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase FetchCount Reading xml ex: {0}, XMLResult: {1}", ex,result),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("FetchCount Ex", ex);
				}
				finally
				{
					if ( rdr != null )
						rdr.Close();
					if ( strm != null )
						strm.Close();
				}
		   }
			catch (SoapException sx)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase FetchCount  sex: {0}-{1}", sx, sx.Detail.InnerText),CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException("FetchCount Sx", sx);
			}
			catch (CRMWrapperException)
			{
				throw;
			}
			catch (Exception ex)
			{
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]CRMWrapperBase FetchCount ex: {0}", ex),CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException("FetchCount Ex", ex);
			}
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase FetchCount Count: {0}", Count),CRMTraceSwitch.Sw.Info);
			return Count;
		}

		#endregion Utilities

		#region Permissions,Privileges, Roles, Business Unit related functions


		/// <summary>
		/// Retrieve all the CRM Privileges
		/// </summary>
		public abstract InternalBusinessEntityCollection GetAllPrivileges();

		/// <summary>
		/// Retrieve all the Privileges for the connected user
		/// </summary>
		public abstract InternalRolePrivilegeArray GetUserPrivileges();

		/// <summary>
		/// Get the connected user's AccessRights for a specific occurence of an entity
		/// Insert it in cache to improve speed
		/// TDB set a dependency for this in the cache
		/// </summary>
		public abstract InternalCrmAccessRights GetAccessRights(string EntName,Guid wGuid);

		/// <summary>
		/// Has the current user rigths on this entity type
		/// </summary>
		public abstract bool HasPermissions(string EntName, ADNCRMRights r );

		#endregion Permissions,Privileges, Roles, Business Unit related functions

		#region BusinessUnits related functions

		/// <summary>
		/// Retrieve all Business Units using admin call, insert them in a sorted dictionnary
		/// </summary>
		public abstract SortedDictionary<Guid,ADNDynBusinessUnit> GetAllBusinessUnits();

		/// <summary>
		/// Find a BU using its Guid
		/// </summary>
		public abstract ADNDynBusinessUnit GetBusinessUnit(Guid businessunitid);

		/// <summary>
		/// Find Name for a Bu given its Guid
		/// </summary>
		public abstract string GetBusinessUnitName(Guid businessunitid);

		#endregion BusinessUnits related functions

		#region roles related functions

		/// <summary>
		/// Renvoie la liste de tous les roles sous forme d'un tableau de roles
		/// </summary>
		public abstract InternalBusinessEntityArray GetAllRoles();

		/// <summary>
		/// Renvoie la liste de tous les noms de roles 
		/// sous forme d'un tableau de strings
		/// </summary>
		public abstract string[] GetStrAllRoles();

		/// <summary>
		/// Renvoie la liste des roles de l'utilisateur sous forme d'un tableau de roles
		/// </summary>
		public abstract InternalBusinessEntityArray GetUserRoles(Guid userId2Test);
 
		/// <summary>
		/// Build an array of strings with names of all roles attached to this user, each element is formated with as 'businessunit.rolename'
		/// </summary>
		public abstract string[] GetStrUserRoles(Guid userId2Test);

		/// <summary>
		/// Try to check if the role sent is amongst the roles of this user
		/// </summary>
		public abstract bool IsInCRMUserRoles(string role2Test,Guid userId2Test);

		#endregion roles related functions

		#region metadata functions
		
		string _LastTimestamp   =   string.Empty;
		public virtual string LastTimestamp
		{
			get
			{
				if ( string.IsNullOrEmpty(_LastTimestamp) )
					_LastTimestamp  =   GetTimestamp();
				return _LastTimestamp;
			}
			set
			{
				_LastTimestamp = value;
			}
		}

		public abstract string GetTimestamp();

		/// <summary>
		/// Provide a way to validate items in cache by comparing timestemp version, valid only for v4
		/// </summary>
		public bool MetadataHasChanged(string lastTimestamp)
		{ 
			return !lastTimestamp.Equals(GetTimestamp());
		} 

		/// <summary>
		/// Used to check presence for a custom entity in crm
		/// </summary>
		public bool ExistEntityMetadata(string entityName)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase ExistEntityMetadata  entityName: {0}", entityName),CRMTraceSwitch.Sw.Info);
			try
			{
				return adminMetaService.ExistEntityMetadata(entityName);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase ExistEntityMetadata sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase ExistEntityMetadata Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					return false;
				throw new CRMWrapperException(msg, sx);
			}
			catch (CRMWrapperException)
			{
				throw;
			}
			catch (Exception ex)
			{
				string msg      =   string.Format("[E]CRMWrapperBase ExistEntityMetadata ex: {0}", ex);
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException(msg, ex);
			}
		}

		public EntityInternalMetadata userRetrieveEntityMetadata(string entityName, EntityInternalItems f)
		{
			return internalRetrieveEntityMetadata(entityName, f, false);
		}
		public EntityInternalMetadata adminRetrieveEntityMetadata(string entityName, EntityInternalItems f)
		{
			return internalRetrieveEntityMetadata(entityName, f, true);
		}

		public EntityInternalMetadata internalRetrieveEntityMetadata(string entityName, EntityInternalItems f, bool isAdmin)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase InternalRetrieveEntityMetadata  entityName: {0}, EntityItems: {1}, isAdmin: {2}", entityName, f,isAdmin),CRMTraceSwitch.Sw.Info);
			try
			{
				if (isAdmin)
					return adminMetaService.RetrieveEntityMetadata(entityName, f);
				return userMetaService.RetrieveEntityMetadata(entityName, f);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase InternalRetrieveEntityMetadata sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase InternalRetrieveEntityMetadata Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (CRMWrapperException)
			{
				throw;
			}
			catch (Exception ex)
			{
				string msg      =   string.Format("[E]CRMWrapperBase InternalRetrieveEntityMetadata ex: {0}", ex);
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException(msg, ex);
			}
		}

		public InternalMetadata userRetrieveMetadata(EntityInternalItems f)
		{
			return internalRetrieveMetadata(f, false);
		}
		public InternalMetadata adminRetrieveMetadata(EntityInternalItems f)
		{
			return internalRetrieveMetadata(f, true);
		}

		public abstract InternalMetadata internalRetrieveMetadata(EntityInternalItems f,bool isAdmin);
	
		/// <summary>
		/// Retrieve the object type code for the specified entity
		/// </summary>
		/// <param name="entityName">Schema name of the entity</param>
		/// <returns>Object type code of entity</returns>
		public abstract int GetObjectTypeCode(string entityName);

		 /// <summary>
		/// Retrieve the display name for the specified entity
		/// </summary>
		public abstract string GetDisplayName(string entityName);

		public InternalAttributeMetadata userRetrieveAttributeMetadata(string entityName, string attributeName)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase adminRetrieveAttributeMetadata  entityName: {0}, attributeName: {1}", entityName,attributeName),CRMTraceSwitch.Sw.Info);
			return internalRetrieveAttributeMetadata(entityName,attributeName,false);
		}
		public InternalAttributeMetadata adminRetrieveAttributeMetadata(string entityName, string attributeName)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase adminRetrieveAttributeMetadata  entityName: {0}, attributeName: {1}", entityName,attributeName),CRMTraceSwitch.Sw.Info);
			return internalRetrieveAttributeMetadata(entityName,attributeName,true);
		}
		
		public InternalAttributeMetadata internalRetrieveAttributeMetadata(string entityName, string attributeName,bool isAdmin)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CRMWrapperBase internalRetrieveAttributeMetadata  entityName: {0}, attributeName: {1}, isAdmin: {2}", entityName,attributeName,isAdmin),CRMTraceSwitch.Sw.Info);
			try
			{
				if (isAdmin )
					return adminMetaService.RetrieveAttributeMetadata(entityName,attributeName);
				return userMetaService.RetrieveAttributeMetadata(entityName,attributeName);
			}
			catch (SoapException sx)
			{
				string msg      =   string.Format("[E]CRMWrapperBase internalRetrieveAttributeMetadata sex: {0}-{1}", sx, sx.Detail.InnerText);
				string errMsg   =   CRMUtil.GetErrorCode(sx);
				if ( errMsg == CrmStr.ObjectNotFound )
					msg         =   "[E]CRMWrapperBase internalRetrieveAttributeMetadata Object not found exception.";
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				if ( errMsg == CrmStr.ObjectNotFound )
					throw new CRMNotFoundException(msg, sx);
				throw new CRMWrapperException(msg, sx);
			}
			catch (CRMWrapperException)
			{
				throw;
			}
			catch (Exception ex)
			{
				string msg      =   string.Format("[E]CRMWrapperBase internalRetrieveAttributeMetadata ex: {0}", ex);
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
				throw new CRMWrapperException(msg, ex);
			}
		}

		public abstract int IterateMetaEntities(EntityInternalItems f, bool isAdmin,bool customOnly,EntityNameDelegate fn);
		
		#endregion metadata functions
		
		#region DynEntity
		
		bool _UseFieldLocalizer     =   false;
		
		/// <summary>
		/// When True try to translate each dynamique entity string property using FieldLocalizer
		/// Default: False
		/// </summary>
		public bool UseFieldLocalizer
		{
			get
			{
				return _UseFieldLocalizer;
			}
			set
			{
				_UseFieldLocalizer = value;
			}
		}

		public abstract PropertyDescriptorCollection StaticCreatePropertyDescriptorCollection(EntityInternalMetadata attribs);
		public abstract PropertyDescriptorCollection CreatePropertyDescriptorCollection(EntityInternalMetadata attributes,DicProperties dicProperties,bool filterWithProperties);
		public abstract void  FillDicProperties(InternalDynamicEntity dEntity,InternalColumnSet ColSel,DicProperties dicProperty);
		public abstract InternalDynamicEntity ToDynamicEntity(DynEntity dn);
		public abstract string GetEntityName(InternalDynamicEntity dEntity);
		public abstract object GetPropertyValue(InternalProperty prop);

		public abstract Guid CreateFromDynEntity(DynEntity dynEnt,bool isAdmin);
		public abstract void UpdateFromDynEntity(DynEntity dynEnt,bool isAdmin);
		public abstract void DeleteFromDynEntity(DynEntity dynEnt,bool isAdmin);
		public abstract bool RetrieveFromDynEntity(DynEntity dynEnt,bool isAdmin);
		public abstract bool RetrieveFromDynEntity(DynEntity dynEnt,InternalColumnSet cols,bool isAdmin);
		public abstract void AssignFromDynEntity(DynEntity dynEnt,Guid wUserId, bool isAdmin);
		
		public abstract InternalActivityParty CreateActivityParty(ADNDynActivityParty edyn);

		#region CRM properties worker methods
		/// <summary>
		/// Helper method to add a string as a StringProperty: creates the property, initializes its key and content, add it tointernal dic.
		/// </summary>
		public abstract StringInternalProperty AddStringProperty(string key, string val,DicProperties dic);
		public abstract CrmBooleanInternalProperty AddBooleanProperty(string key, Boolean val,DicProperties dic);
		public abstract CrmDateTimeInternalProperty AddDateTimeProperty(String name, string value,DicProperties dic);
		public virtual CrmDateTimeInternalProperty AddDateTimeProperty(String name,DateTime value,bool isUserTime,DicProperties dic)
		{
			if ( isUserTime )
				return AddDateTimeProperty(name,CRMUtil.CreateDateTimeFromUser(value),dic);
			return AddDateTimeProperty(name,CRMUtil.CreateCrmDateTimeFromUniversal(value),dic);
		}
		public abstract CrmDecimalInternalProperty AddDecimalProperty(String name, Decimal value,DicProperties dic);
		public abstract CrmFloatInternalProperty AddFloatProperty(String name, double value,DicProperties dic); // v3 only supports float
		public abstract CrmFloatInternalProperty AddFloatProperty(String name, float value,DicProperties dic);
		public abstract CrmMoneyInternalProperty AddMoneyProperty(String name, Decimal value,DicProperties dic);
		public abstract CrmNumberInternalProperty AddNumberProperty(String name, int value,DicProperties dic);
		public abstract CustomerInternalProperty AddCustomerProperty(string name, string type, Guid value,DicProperties dic);
		public abstract DynamicEntityArrayInternalProperty AddDynamicEntityArrayProperty(String name, InternalDynamicEntityArray value,DicProperties dic);
		public abstract EntityNameReferenceInternalProperty AddEntityNameReferenceProperty(String name, string value,DicProperties dic);
		public abstract KeyInternalProperty AddKeyProperty(String name, Guid value,DicProperties dic);
		public abstract LookupInternalProperty AddLookupProperty(String name, String type, Guid value,DicProperties dic);
		public abstract CalendarRulesInternalProperty AddCalendarRulesProperty(string name,object value,DicProperties dicProperty);
		public abstract OwnerInternalProperty AddOwnerProperty(String name, String type, Guid value,DicProperties dic);
		public abstract PicklistInternalProperty AddPicklistProperty(String name, int value,DicProperties dic);
		public abstract StateInternalProperty AddStateProperty(String name, String value,DicProperties dic);
		public abstract StatusInternalProperty AddStatusProperty(String name, int value,DicProperties dic);
		public abstract UniqueIdentifierInternalProperty AddUniqueIdentifierProperty(String name, Guid value,DicProperties dic);

		#endregion CRM properties worker methods

		#region Extracting Properties values

		/// <summary>
		/// beware that when a string value is string.empty, CRM server web services doesn't return the corresponding property
		/// This is a bad conception and to live with this, we must return string.Empywhen the value is not found.
		/// This could also mean that the attribut is not present....
		/// </summary>
		public abstract string StringPropertyValue(string key,DicProperties dic);
		public string StringPropertyValueEx(DynEntity dyn,string key,int LCID)
		{            return dyn.StringPropertyValueEx(key,LCID);}
		public abstract bool IsBooleanPropertyValueNull(string key,DicProperties dic);
		public abstract bool BooleanPropertyValue(string key,DicProperties dic);
		public abstract string DateTimePropertyValue(string key,DicProperties dic);
		public abstract DateTime DateTimePropertyDate(string key,DicProperties dic,bool toLocalTime);
		public abstract bool IsDecimalPropertyValueNull(string key,DicProperties dic);
		public abstract decimal DecimalPropertyValue(string key,DicProperties dic);
		public abstract bool IsFloatPropertyValueNull(string key,DicProperties dic);
		[Obsolete("warning: should better use DoublePropertyValue to avoid loosing precision in crm 4")]
		public abstract float FloatPropertyValue(string key,DicProperties dic);
		/// <summary>
		/// In fact a FloatProperty but Crm3 uses float and Crm 4 uses double
		/// </summary>
		public abstract double DoublePropertyValue(string key,DicProperties dic);
		public abstract bool IsMoneyPropertyValueNull(string key,DicProperties dic);
		public abstract decimal MoneyPropertyValue(string key,DicProperties dic);
		public abstract bool IsNumberPropertyValueNull(string key,DicProperties dic);
		public abstract int NumberPropertyValue(string key,DicProperties dic);
		public abstract bool IsUniqueIdentifierPropertyValueNull(string key,DicProperties dic);
		public abstract Guid UniqueIdentifierPropertyValue(string key,DicProperties dic);
		public abstract bool IsPicklistPropertyIntValueNull(string key,DicProperties dic);
		public abstract int PicklistPropertyIntValue(string key,DicProperties dic);
		public abstract string PicklistPropertyNameValue(string key,DicProperties dic);
		public abstract string EntityNameReferencePropertyValue(string key,DicProperties dic);
		public abstract Guid KeyPropertyValue(string key,DicProperties dic);
		public abstract bool  IsLookupPropertyValueNull(string key,DicProperties dic);
		public abstract string LookupPropertyType(string key,DicProperties dic);
		public abstract string LookupPropertyName(string key,DicProperties dic);
		public abstract Guid LookupPropertyValue(string key,DicProperties dic);
		public abstract object CalendarRulesPropertyValue(string key,DicProperties dic);
		public abstract int CalendarRulesPropertyLength(string key,DicProperties dic);
		public abstract object CalendarRulesPropertyAtIndex(string key,DicProperties dic,int idx);
		public abstract Guid CalendarRulesPropertyLookupAtIndex(string key,DicProperties dic,int idx);
		public abstract bool IsOwnerPropertyValueNull(string key,DicProperties dic);
		public abstract Guid OwnerPropertyValue(string key,DicProperties dic);
		public abstract string OwnerPropertyName(string key,DicProperties dic);
		public abstract string OwnerPropertyType(string key,DicProperties dic);
		public abstract bool IsCustomerPropertyValueNull(string key,DicProperties dic);
		public abstract Guid CustomerPropertyValue(string key,DicProperties dic);
		public abstract string CustomerPropertyName(string key,DicProperties dic);
		public abstract string CustomerPropertyType(string key,DicProperties dic);
		public abstract InternalDynamicEntityArray DynamicEntityArrayProperty(String key,DicProperties dic);
		public abstract string StatePropertyValue(string key,DicProperties dic);
		public abstract string IncidentStatePropertyValue(string key,DicProperties dic);
		public abstract string StatePropertyNameValue(string key,DicProperties dic);
		public abstract int StatusPropertyIntValue(string key,DicProperties dic);
		public abstract string StatusPropertyNameValue(string key,DicProperties dic);
		#endregion Extracting Properties values
		
		#region used by EntityList
		public abstract List<string> GetEntityList();
		#endregion used by EntityList

		#region Serialize / Deserialize 
		
		public abstract string Serialize(DynEntity dyn);
		public abstract T Deserialize<T>(ResetWrapperHandler fnr,string xml)  where T : DynEntity, new();

		#endregion Serialize / Deserialize 
		
		#region InitializeFrom
		
		public enum TargetFieldType: int
		{
			All             =   0,// Specifies to initialize all possible properties. 
			ValidForCreate  =   1,// Specifies to initialize the properties that are valid for create. 
			ValidForRead    =   3,// Specifies to initialize the properties that are valid for read. 
			ValidForUpdate  =   2 //Specifies to initialize the properties that are valid for update. 
		}

		public abstract Guid InitializeFrom(DynEntity dyn,string targetEntity,bool isAdmin);

		#endregion InitializeFrom
		
		#endregion dynEntity
	}
}
